// src/quat.ts
/**
 * 高性能四元数运算库
 * 基于 Float32Array 实现，支持四元数创建、运算、插值及与矩阵/欧拉角的转换
 * 矩阵采用列优先存储（适配 WebGL/OpenGL 标准）
 * @module quat
 */

// ==========================================
// 类型定义
// ==========================================

/**
 * 四元数类型（基于 Float32Array，固定长度 4）
 * 存储格式：[x, y, z, w]（虚部 x,y,z，实部 w）
 */
export type Quat = Float32Array & { length: 4 };

/**
 * 只读四元数类型
 */
export type ReadonlyQuat = Readonly<Float32Array> & { length: 4 };

/**
 * 三维向量类型（基于 Float32Array，固定长度 3）
 * 存储格式：[x, y, z]
 */
export type Vec3 = Float32Array & { length: 3 };

/**
 * 只读三维向量类型
 */
export type ReadonlyVec3 = Readonly<Float32Array> & { length: 3 };

/**
 * 3x3 矩阵类型（基于 Float32Array，固定长度 9）
 * 存储格式：列优先 [m00, m10, m20, m01, m11, m21, m02, m12, m22]
 * 对应矩阵：
 * [ m00  m01  m02 ]
 * [ m10  m11  m12 ]
 * [ m20  m21  m22 ]
 */
export type Mat3 = Float32Array & { length: 9 };

/**
 * 只读 3x3 矩阵类型
 */
export type ReadonlyMat3 = Readonly<Float32Array> & { length: 9 };

// ==========================================
// 常量定义
// ==========================================

/**
 * 浮点精度误差阈值（用于近似比较）
 */
const EPSILON = 1e-6;

// ==========================================
// 四元数创建与基础操作
// ==========================================

/**
 * 创建单位四元数 [0, 0, 0, 1]
 * @returns 新的单位四元数实例
 * @example
 * const q = quat.create(); // 结果：[0, 0, 0, 1]
 */
export function create(): Quat {
  const q = new Float32Array(4);
  q[3] = 1; // 单位四元数实部为 1
  return q as Quat;
}

/**
 * 将四元数重置为单位四元数
 * @param out 输出四元数（将被修改）
 * @returns 重置后的单位四元数（与 out 指向同一对象）
 * @example
 * const q = quat.create();
 * quat.set(1, 2, 3, 4, q);
 * quat.identity(q); // q 变为 [0, 0, 0, 1]
 */
export function identity(out: Quat): Quat {
  out[0] = 0;
  out[1] = 0;
  out[2] = 0;
  out[3] = 1;
  return out;
}

/**
 * 从旋转轴和角度创建四元数（弧度制）
 * @param axis 旋转轴向量（支持普通数组 [x,y,z] 或 Vec3，建议单位化）
 * @param angle 旋转角度（弧度制，右手螺旋法则）
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 基于轴角的四元数
 * @example
 * // 绕 Y 轴旋转 90°（π/2 弧度）
 * const q = quat.from([0, 1, 0], Math.PI / 2);
 */
export function from(
  axis: [number, number, number] | ReadonlyVec3,
  angle: number,
  out?: Quat
): Quat {
  out ||= new Float32Array(4) as Quat;
  const halfAngle = angle * 0.5;
  const sinHalf = Math.sin(halfAngle);
  out[0] = axis[0] * sinHalf;
  out[1] = axis[1] * sinHalf;
  out[2] = axis[2] * sinHalf;
  out[3] = Math.cos(halfAngle);
  return out;
}

/**
 * 从 XYZ 欧拉角创建四元数（弧度制，旋转顺序 X→Y→Z，与 Three.js 兼容）
 * @param x 绕 X 轴旋转角度（弧度，俯仰角）
 * @param y 绕 Y 轴旋转角度（弧度，偏航角）
 * @param z 绕 Z 轴旋转角度（弧度，翻滚角）
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 转换后的四元数
 * @example
 * // X 轴旋转 90°，Y、Z 轴不旋转
 * const q = quat.of(Math.PI / 2, 0, 0);
 */
export function of(x: number, y: number, z: number, out?: Quat): Quat {
  out ||= new Float32Array(4) as Quat;
  const hx = x * 0.5, hy = y * 0.5, hz = z * 0.5;
  const sx = Math.sin(hx), cx = Math.cos(hx);
  const sy = Math.sin(hy), cy = Math.cos(hy);
  const sz = Math.sin(hz), cz = Math.cos(hz);
  out[0] = sx * cy * cz + cx * sy * sz;
  out[1] = cx * sy * cz - sx * cy * sz;
  out[2] = cx * cy * sz + sx * sy * cz;
  out[3] = cx * cy * cz - sx * sy * sz;
  return out;
}

/**
 * 从分量值创建四元数
 * @param x 虚部 x 分量
 * @param y 虚部 y 分量
 * @param z 虚部 z 分量
 * @param w 实部 w 分量
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 新的四元数
 * @example
 * const q = quat.set(0.5, 0.5, 0, 0.707);
 */
export function set(x: number, y: number, z: number, w: number, out: Quat = create()): Quat {
  out[0] = x;
  out[1] = y;
  out[2] = z;
  out[3] = w;
  return out;
}

// ==========================================
// 四元数运算
// ==========================================

/**
 * 四元数乘法（out = a * b，旋转复合）
 * 几何意义：先应用 b 旋转，再应用 a 旋转
 * @param a 第一个四元数（右操作数）
 * @param b 第二个四元数（左操作数）
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 乘积结果
 * @example
 * const q1 = quat.from([1,0,0], Math.PI/2); // X轴旋转90°
 * const q2 = quat.from([0,1,0], Math.PI/2); // Y轴旋转90°
 * const q = quat.multiply(q1, q2); // 先Y后X的复合旋转
 */
export function multiply(a: ReadonlyQuat, b: ReadonlyQuat, out: Quat = create()): Quat {
  const ax = a[0], ay = a[1], az = a[2], aw = a[3];
  const bx = b[0], by = b[1], bz = b[2], bw = b[3];
  out[0] = ax * bw + aw * bx + ay * bz - az * by;
  out[1] = ay * bw + aw * by + az * bx - ax * bz;
  out[2] = az * bw + aw * bz + ax * by - ay * bx;
  out[3] = aw * bw - ax * bx - ay * by - az * bz;
  return out;
}

/**
 * 四元数加法（out = a + b）
 * @param a 第一个四元数
 * @param b 第二个四元数
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 和四元数
 * @example
 * const q1 = quat.create();
 * const q2 = quat.set(1, 2, 3, 4);
 * const q = quat.add(q1, q2); // 结果：[1, 2, 3, 5]
 */
export function add(a: ReadonlyQuat, b: ReadonlyQuat, out: Quat = create()): Quat {
  out[0] = a[0] + b[0];
  out[1] = a[1] + b[1];
  out[2] = a[2] + b[2];
  out[3] = a[3] + b[3];
  return out;
}

/**
 * 四元数缩放（out = a * s）
 * @param a 输入四元数
 * @param s 缩放因子
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 缩放后的四元数
 * @example
 * const q = quat.set(1, 1, 1, 1);
 * quat.scale(q, 0.5, q); // q 变为 [0.5, 0.5, 0.5, 0.5]
 */
export function scale(a: ReadonlyQuat, s: number, out: Quat = create()): Quat {
  out[0] = a[0] * s;
  out[1] = a[1] * s;
  out[2] = a[2] * s;
  out[3] = a[3] * s;
  return out;
}

/**
 * 计算四元数的共轭（虚部取反）
 * @param a 输入四元数
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 共轭四元数
 * @example
 * const q = quat.set(1, 2, 3, 4);
 * const conj = quat.conjugate(q); // 结果：[-1, -2, -3, 4]
 */
export function conjugate(a: ReadonlyQuat, out: Quat = create()): Quat {
  out[0] = -a[0];
  out[1] = -a[1];
  out[2] = -a[2];
  out[3] = a[3];
  return out;
}

/**
 * 计算四元数的逆（对于单位四元数，逆等于共轭）
 * @param a 输入四元数
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 逆四元数
 * @example
 * const q = quat.from([0,1,0], Math.PI/2); // 单位四元数
 * const inv = quat.invert(q); // 结果等于 q 的共轭
 */
export function invert(a: ReadonlyQuat, out: Quat = create()): Quat {
  const lenSq = squaredLength(a);
  const invLenSq = lenSq > 0 ? 1 / lenSq : 0;
  out[0] = -a[0] * invLenSq;
  out[1] = -a[1] * invLenSq;
  out[2] = -a[2] * invLenSq;
  out[3] = a[3] * invLenSq;
  return out;
}

/**
 * 归一化四元数（单位化）
 * @param a 输入四元数
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 单位四元数
 * @example
 * const q = quat.set(2, 0, 0, 2);
 * const norm = quat.normalize(q); // 结果：[√2/2, 0, 0, √2/2]
 */
export function normalize(a: ReadonlyQuat, out: Quat = create()): Quat {
  const len = length(a);
  const invLen = len > 0 ? 1 / len : 0;
  out[0] = a[0] * invLen;
  out[1] = a[1] * invLen;
  out[2] = a[2] * invLen;
  out[3] = a[3] * invLen;
  return out;
}

// ==========================================
// 插值方法
// ==========================================

/**
 * 球面线性插值（SLERP）- 保持旋转角速度恒定
 * @param a 起始四元数
 * @param b 目标四元数
 * @param t 插值因子（0~1，0 对应 a，1 对应 b）
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 插值结果
 * @example
 * const q1 = quat.from([1,0,0], 0); // 单位四元数
 * const q2 = quat.from([1,0,0], Math.PI); // X轴旋转180°
 * const q = quat.slerp(q1, q2, 0.5); // 插值到90°
 */
export function slerp(a: ReadonlyQuat, b: ReadonlyQuat, t: number, out: Quat = create()): Quat {
  let ax = a[0], ay = a[1], az = a[2], aw = a[3];
  let bx = b[0], by = b[1], bz = b[2], bw = b[3];

  let cosom = dot(a, b);
  if (cosom < 0) {
    cosom = -cosom;
    bx = -bx;
    by = -by;
    bz = -bz;
    bw = -bw;
  }

  let s0, s1;
  if (1 - cosom > EPSILON) {
    const omega = Math.acos(cosom);
    const invSin = 1 / Math.sin(omega);
    s0 = Math.sin((1 - t) * omega) * invSin;
    s1 = Math.sin(t * omega) * invSin;
  } else {
    s0 = 1 - t;
    s1 = t;
  }

  out[0] = s0 * ax + s1 * bx;
  out[1] = s0 * ay + s1 * by;
  out[2] = s0 * az + s1 * bz;
  out[3] = s0 * aw + s1 * bw;
  return out;
}

/**
 * 线性插值（LERP）- 速度不均匀，结果需手动归一化
 * @param a 起始四元数
 * @param b 目标四元数
 * @param t 插值因子（0~1）
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 插值结果（非单位四元数，需归一化后使用）
 * @example
 * const q1 = quat.create();
 * const q2 = quat.from([0,1,0], Math.PI/2);
 * const q = quat.lerp(q1, q2, 0.5);
 * quat.normalize(q, q); // 归一化后使用
 */
export function lerp(a: ReadonlyQuat, b: ReadonlyQuat, t: number, out: Quat = create()): Quat {
  out[0] = a[0] + t * (b[0] - a[0]);
  out[1] = a[1] + t * (b[1] - a[1]);
  out[2] = a[2] + t * (b[2] - a[2]);
  out[3] = a[3] + t * (b[3] - a[3]);
  return out;
}

/**
 * 带控制点的球面插值（SQ lerp）- 用于平滑动画过渡
 * @param a 起点四元数
 * @param b 控制点1
 * @param c 控制点2
 * @param d 终点四元数
 * @param t 插值因子（0~1）
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 插值结果
 * @example
 * const qStart = quat.create();
 * const qCtrl1 = quat.from([1,0,0], Math.PI/4);
 * const qCtrl2 = quat.from([1,0,0], Math.PI/2);
 * const qEnd = quat.from([1,0,0], Math.PI);
 * const q = quat.sqlerp(qStart, qCtrl1, qCtrl2, qEnd, 0.5);
 */
export function sqlerp(
  a: ReadonlyQuat,
  b: ReadonlyQuat,
  c: ReadonlyQuat,
  d: ReadonlyQuat,
  t: number,
  out: Quat = create()
): Quat {
  const temp1 = create();
  const temp2 = create();
  slerp(a, d, t, temp1);
  slerp(b, c, t, temp2);
  return slerp(temp1, temp2, 2 * t * (1 - t), out);
}

// ==========================================
// 点旋转方法
// ==========================================

/**
 * 将四元数表示的旋转应用到三维点上
 * 旋转公式：p' = q * p * q⁻¹（其中 p 为纯四元数 [x,y,z,0]，q⁻¹ 为 q 的逆）
 * @param q 旋转四元数（单位四元数）
 * @param point 待旋转的点（支持普通数组 [x,y,z] 或 Vec3）
 * @param [out] 输出旋转后的点（可选，若不提供则自动创建）
 * @returns 旋转后的点
 * @example
 * const q = quat.from([0,1,0], Math.PI/2); // 绕Y轴旋转90°
 * const point = [1, 0, 0]; // X轴上的点
 * const rotated = quat.rotatePoint(q, point); // 结果：[0, 0, 1]
 */
export function rotatePoint(
  q: ReadonlyQuat,
  point: [number, number, number] | ReadonlyVec3,
  out?: Vec3
): Vec3 {
  out ||= new Float32Array(3) as Vec3;
  const qx = q[0], qy = q[1], qz = q[2], qw = q[3];
  const x = point[0], y = point[1], z = point[2];

  // 计算 q * p
  const ix = qw * x + qy * z - qz * y;
  const iy = qw * y + qz * x - qx * z;
  const iz = qw * z + qx * y - qy * x;
  const iw = -qx * x - qy * y - qz * z;

  // 计算 (q*p) * q⁻¹
  out[0] = ix * qw + iw * qx + iy * qz - iz * qy;
  out[1] = iy * qw + iw * qy + iz * qx - ix * qz;
  out[2] = iz * qw + iw * qz + ix * qy - iy * qx;

  return out;
}

/**
 * 批量将四元数旋转应用到多个三维点上
 * @param q 旋转四元数（单位四元数）
 * @param points 待旋转的点数组（格式：[x1,y1,z1,x2,y2,z2,...]，长度需为3的倍数）
 * @param out 输出旋转后的点数组（格式同上，长度需与 points 一致）
 * @returns 旋转后的点数组（与 out 指向同一对象）
 * @throws 若 points 与 out 长度不一致或不为3的倍数则抛出错误
 * @example
 * const q = quat.from([0,1,0], Math.PI/2); // 绕Y轴旋转90°
 * const points = new Float32Array([1,0,0, 0,0,1]); // 两个点
 * const out = new Float32Array(points.length);
 * quat.rotatePoints(q, points, out); // out 结果：[0,0,1, -1,0,0]
 */
export function rotatePoints(
  q: ReadonlyQuat,
  points: Float32Array,
  out: Float32Array
): Float32Array {
  if (points.length !== out.length) {
    throw new Error("输入点数组与输出数组长度必须一致");
  }
  if (points.length % 3 !== 0) {
    throw new Error("点数组长度必须为3的倍数");
  }

  const qx = q[0], qy = q[1], qz = q[2], qw = q[3];
  for (let i = 0; i < points.length; i += 3) {
    const x = points[i];
    const y = points[i + 1];
    const z = points[i + 2];

    const ix = qw * x + qy * z - qz * y;
    const iy = qw * y + qz * x - qx * z;
    const iz = qw * z + qx * y - qy * x;
    const iw = -qx * x - qy * y - qz * z;

    out[i] = ix * qw + iw * qx + iy * qz - iz * qy;
    out[i + 1] = iy * qw + iw * qy + iz * qx - ix * qz;
    out[i + 2] = iz * qw + iw * qz + ix * qy - iy * qx;
  }

  return out;
}

// ==========================================
// 转换方法（矩阵/轴角/欧拉角）
// ==========================================

/**
 * 从 3x3 旋转矩阵创建四元数（矩阵采用列优先存储）
 * @param m 3x3 旋转矩阵（列优先）
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 转换后的四元数
 * @example
 * // 列优先单位矩阵
 * const mat = new Float32Array([1,0,0, 0,1,0, 0,0,1]) as quat.Mat3;
 * const q = quat.fromMat3(mat); // 结果为单位四元数
 */
export function fromMat3(m: ReadonlyMat3, out: Quat = create()): Quat {
  const m00 = m[0], m10 = m[1], m20 = m[2];
  const m01 = m[3], m11 = m[4], m21 = m[5];
  const m02 = m[6], m12 = m[7], m22 = m[8];

  const trace = m00 + m11 + m22;
  if (trace > 0) {
    const s = Math.sqrt(trace + 1) * 2;
    out[0] = (m12 - m21) / s;
    out[1] = (m20 - m02) / s;
    out[2] = (m01 - m10) / s;
    out[3] = 0.25 * s;
  } else if (m00 > m11 && m00 > m22) {
    const s = Math.sqrt(1 + m00 - m11 - m22) * 2;
    out[0] = 0.25 * s;
    out[1] = (m01 + m10) / s;
    out[2] = (m20 + m02) / s;
    out[3] = (m12 - m21) / s;
  } else if (m11 > m22) {
    const s = Math.sqrt(1 + m11 - m00 - m22) * 2;
    out[0] = (m01 + m10) / s;
    out[1] = 0.25 * s;
    out[2] = (m12 + m21) / s;
    out[3] = (m20 - m02) / s;
  } else {
    const s = Math.sqrt(1 + m22 - m00 - m11) * 2;
    out[0] = (m20 + m02) / s;
    out[1] = (m12 + m21) / s;
    out[2] = 0.25 * s;
    out[3] = (m01 - m10) / s;
  }
  return out;
}

/**
 * 将四元数转换为 3x3 旋转矩阵（列优先存储，适配 WebGL）
 * @param q 输入四元数
 * @param [out] 输出矩阵（可选，若不提供则自动创建）
 * @returns 3x3 旋转矩阵（列优先）
 * @example
 * const q = quat.from([0,1,0], Math.PI/2); // Y轴旋转90°
 * const mat = quat.toMat3(q); // 列优先旋转矩阵
 */
export function toMat3(q: ReadonlyQuat, out: Mat3 = new Float32Array(9) as Mat3): Mat3 {
  const x = q[0], y = q[1], z = q[2], w = q[3];
  const x2 = x + x, y2 = y + y, z2 = z + z;
  const xx = x * x2, xy = x * y2, xz = x * z2;
  const yy = y * y2, yz = y * z2, zz = z * z2;
  const wx = w * x2, wy = w * y2, wz = w * z2;

  // 列优先矩阵赋值：[m00, m10, m20, m01, m11, m21, m02, m12, m22]
  out[0] = 1 - (yy + zz); // m00
  out[1] = xy - wz;       // m10
  out[2] = xz + wy;       // m20
  out[3] = xy + wz;       // m01
  out[4] = 1 - (xx + zz); // m11
  out[5] = yz - wx;       // m21
  out[6] = xz - wy;       // m02
  out[7] = yz + wx;       // m12
  out[8] = 1 - (xx + yy); // m22
  return out;
}

/**
 * 从四元数提取旋转轴和角度
 * @param outAxis 输出旋转轴（将被修改）
 * @param q 输入四元数
 * @returns 旋转角度（弧度制）
 * @example
 * const q = quat.from([0,1,0], Math.PI/2);
 * const axis = new Float32Array(3) as quat.Vec3;
 * const angle = quat.getAxisAngle(axis, q); // angle = π/2, axis = [0,1,0]
 */
export function getAxisAngle(outAxis: Vec3, q: ReadonlyQuat): number {
  const rad = Math.acos(q[3]) * 2;
  const s = Math.sin(rad / 2);
  if (s > EPSILON) {
    outAxis[0] = q[0] / s;
    outAxis[1] = q[1] / s;
    outAxis[2] = q[2] / s;
  } else {
    outAxis[0] = 1;
    outAxis[1] = 0;
    outAxis[2] = 0;
  }
  return rad;
}

// ==========================================
// 辅助方法（长度、点积、比较等）
// ==========================================

/**
 * 计算四元数的长度（模长）
 * @param a 输入四元数
 * @returns 长度值
 * @example
 * const q = quat.set(1, 0, 0, 0);
 * console.log(quat.length(q)); // 输出：1
 */
export function length(a: ReadonlyQuat): number {
  return Math.sqrt(squaredLength(a));
}

/**
 * 计算四元数的平方长度（避免开方，性能更高）
 * @param a 输入四元数
 * @returns 平方长度值
 * @example
 * const q = quat.set(1, 1, 0, 0);
 * console.log(quat.squaredLength(q)); // 输出：2
 */
export function squaredLength(a: ReadonlyQuat): number {
  return a[0] **2 + a[1]** 2 + a[2] **2 + a[3]** 2;
}

/**
 * 计算两个四元数的点积
 * @param a 第一个四元数
 * @param b 第二个四元数
 * @returns 点积结果
 * @example
 * const q1 = quat.set(1, 2, 3, 4);
 * const q2 = quat.set(5, 6, 7, 8);
 * console.log(quat.dot(q1, q2)); // 输出：70
 */
export function dot(a: ReadonlyQuat, b: ReadonlyQuat): number {
  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
}

/**
 * 检查两个四元数是否完全相等（严格比较，不考虑浮点误差）
 * @param a 第一个四元数
 * @param b 第二个四元数
 * @returns 是否完全相等
 * @example
 * const q1 = quat.set(1, 2, 3, 4);
 * const q2 = quat.set(1, 2, 3, 4);
 * console.log(quat.exactEquals(q1, q2)); // 输出：true
 */
export function exactEquals(a: ReadonlyQuat, b: ReadonlyQuat): boolean {
  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
}

/**
 * 检查两个四元数是否近似相等（考虑浮点误差）
 * @param a 第一个四元数
 * @param b 第二个四元数
 * @returns 是否近似相等
 * @example
 * const q1 = quat.set(1, 0, 0, 0);
 * const q2 = quat.set(1 + 1e-7, 0, 0, 0);
 * console.log(quat.equals(q1, q2)); // 输出：true
 */
export function equals(a: ReadonlyQuat, b: ReadonlyQuat): boolean {
  return Math.abs(dot(a, b)) >= 1 - EPSILON;
}

// ==========================================
// 工具方法（克隆、复制、类型转换等）
// ==========================================

/**
 * 克隆四元数
 * @param a 输入四元数
 * @returns 克隆的新四元数
 * @example
 * const q1 = quat.from([0,1,0], Math.PI/2);
 * const q2 = quat.clone(q1); // q2 是 q1 的副本
 */
export function clone(a: ReadonlyQuat): Quat {
  const out = new Float32Array(4);
  out.set(a);
  return out as Quat;
}

/**
 * 复制四元数到目标对象
 * @param a 源四元数
 * @param out 目标四元数（将被修改）
 * @returns 复制后的四元数（与 out 指向同一对象）
 * @example
 * const q1 = quat.from([0,1,0], Math.PI/2);
 * const q2 = quat.create();
 * quat.copy(q1, q2); // q2 现在与 q1 相等
 */
export function copy(a: ReadonlyQuat, out: Quat): Quat {
  out.set(a);
  return out;
}

/**
 * 从普通数组转换为四元数
 * @param arr 长度为4的普通数组 [x, y, z, w]
 * @returns 新的四元数
 * @throws 若数组长度不为4则抛出错误
 * @example
 * const arr = [0, 0, 0, 1];
 * const q = quat.fromArray(arr); // 转换为四元数
 */
export function fromArray(arr: number[]): Quat {
  if (arr.length !== 4) throw new Error("数组长度必须为4");
  const out = new Float32Array(4);
  out.set(arr);
  return out as Quat;
}

/**
 * 将四元数转换为普通数组
 * @param q 输入四元数
 * @returns 普通数组 [x, y, z, w]
 * @example
 * const q = quat.create();
 * const arr = quat.toArray(q); // 结果：[0, 0, 0, 1]
 */
export function toArray(q: ReadonlyQuat): number[] {
  return [q[0], q[1], q[2], q[3]];
}

/**
 * 将四元数转换为字符串表示
 * @param a 输入四元数
 * @returns 格式化的字符串（保留6位小数）
 * @example
 * const q = quat.from([0,1,0], Math.PI/2);
 * console.log(quat.str(q)); // 输出：quat(0.707107, 0.000000, 0.000000, 0.707107)
 */
export function str(a: ReadonlyQuat): string {
  return `quat(${a[0].toFixed(6)}, ${a[1].toFixed(6)}, ${a[2].toFixed(6)}, ${a[3].toFixed(6)})`;
}

/**
 * 生成随机单位四元数
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 随机单位四元数
 * @example
 * const q = quat.random(); // 随机旋转四元数
 */
export function random(out: Quat = create()): Quat {
  const u1 = Math.random();
  const u2 = Math.random();
  const u3 = Math.random();
  const sqrt1u1 = Math.sqrt(1 - u1);
  const sqrtU1 = Math.sqrt(u1);
  out[0] = sqrt1u1 * Math.sin(2 * Math.PI * u2);
  out[1] = sqrt1u1 * Math.cos(2 * Math.PI * u2);
  out[2] = sqrtU1 * Math.sin(2 * Math.PI * u3);
  out[3] = sqrtU1 * Math.cos(2 * Math.PI * u3);
  return out;
}

/**
 * 计算四元数的指数
 * @param a 输入四元数
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 指数运算结果
 * @example
 * const q = quat.set(0, 0, Math.PI/4, 0);
 * const expQ = quat.exp(q); // 等价于绕Z轴旋转π/2的四元数
 */
export function exp(a: ReadonlyQuat, out: Quat = create()): Quat {
  const x = a[0], y = a[1], z = a[2], w = a[3];
  const r = Math.sqrt(x * x + y * y + z * z);
  const et = Math.exp(w);
  const s = r > 0 ? (et * Math.sin(r)) / r : 0;
  out[0] = x * s;
  out[1] = y * s;
  out[2] = z * s;
  out[3] = et * Math.cos(r);
  return out;
}

/**
 * 计算四元数的自然对数
 * @param a 输入四元数
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 对数运算结果
 * @example
 * const q = quat.from([0,0,1], Math.PI/2);
 * const lnQ = quat.ln(q); // 结果：[0, 0, π/4, 0]
 */
export function ln(a: ReadonlyQuat, out: Quat = create()): Quat {
  const x = a[0], y = a[1], z = a[2], w = a[3];
  const r = Math.sqrt(x * x + y * y + z * z);
  const t = r > 0 ? Math.atan2(r, w) / r : 0;
  out[0] = x * t;
  out[1] = y * t;
  out[2] = z * t;
  out[3] = 0.5 * Math.log(squaredLength(a));
  return out;
}

/**
 * 计算四元数的标量幂（a^b）
 * @param a 输入四元数
 * @param b 幂值（标量）
 * @param [out] 输出四元数（可选，若不提供则自动创建）
 * @returns 幂运算结果
 * @example
 * const q = quat.from([0,0,1], Math.PI); // 绕Z轴旋转180°
 * const qPow = quat.pow(q, 0.5); // 结果：绕Z轴旋转90°
 */
export function pow(a: ReadonlyQuat, b: number, out: Quat = create()): Quat {
  ln(a, out);
  scale(out, b);
  exp(out, out);
  return out;
}

// ==========================================
// 类型守卫（运行时类型检查）
// ==========================================

/**
 * 类型守卫：检查值是否为四元数
 * @param value 待检查的值
 * @returns 若为四元数则返回 true，否则返回 false
 * @example
 * const q = quat.create();
 * console.log(quat.isQuat(q)); // 输出：true
 */
export function isQuat(value: unknown): value is Quat {
  return value instanceof Float32Array && value.length === 4;
}

/**
 * 类型守卫：检查值是否为三维向量
 * @param value 待检查的值
 * @returns 若为三维向量则返回 true，否则返回 false
 * @example
 * const v = new Float32Array(3) as quat.Vec3;
 * console.log(quat.isVec3(v)); // 输出：true
 */
export function isVec3(value: unknown): value is Vec3 {
  return value instanceof Float32Array && value.length === 3;
}